/**
 * 加密工具函数
 * @author Wu.Liang
 * @date 2025-01-21
 */

import CryptoJS from 'crypto-js'

/**
 * 加密配置
 */
const CRYPTO_CONFIG = {
  // AES加密密钥
  AES_KEY: 'smart-community-app-key-2025',
  // AES加密向量
  AES_IV: 'smart-community-iv',
  // 加密算法
  ALGORITHM: 'AES-256-CBC'
}

/**
 * AES加密
 * @param {string|object} data 要加密的数据
 * @param {string} key 加密密钥
 * @returns {string} 加密后的字符串
 */
export const aesEncrypt = (data, key = CRYPTO_CONFIG.AES_KEY) => {
  try {
    const dataStr = typeof data === 'object' ? JSON.stringify(data) : String(data)
    const encrypted = CryptoJS.AES.encrypt(dataStr, key, {
      mode: CryptoJS.mode.CBC,
      padding: CryptoJS.pad.Pkcs7,
      iv: CryptoJS.enc.Utf8.parse(CRYPTO_CONFIG.AES_IV)
    })
    return encrypted.toString()
  } catch (error) {
    console.error('AES加密失败:', error)
    return ''
  }
}

/**
 * AES解密
 * @param {string} encryptedData 加密后的数据
 * @param {string} key 解密密钥
 * @returns {string|object} 解密后的数据
 */
export const aesDecrypt = (encryptedData, key = CRYPTO_CONFIG.AES_KEY) => {
  try {
    const decrypted = CryptoJS.AES.decrypt(encryptedData, key, {
      mode: CryptoJS.mode.CBC,
      padding: CryptoJS.pad.Pkcs7,
      iv: CryptoJS.enc.Utf8.parse(CRYPTO_CONFIG.AES_IV)
    })
    const decryptedStr = decrypted.toString(CryptoJS.enc.Utf8)
    
    // 尝试解析为JSON对象
    try {
      return JSON.parse(decryptedStr)
    } catch {
      return decryptedStr
    }
  } catch (error) {
    console.error('AES解密失败:', error)
    return ''
  }
}

/**
 * MD5哈希
 * @param {string} data 要哈希的数据
 * @returns {string} MD5哈希值
 */
export const md5 = (data) => {
  try {
    return CryptoJS.MD5(String(data)).toString()
  } catch (error) {
    console.error('MD5哈希失败:', error)
    return ''
  }
}

/**
 * SHA256哈希
 * @param {string} data 要哈希的数据
 * @returns {string} SHA256哈希值
 */
export const sha256 = (data) => {
  try {
    return CryptoJS.SHA256(String(data)).toString()
  } catch (error) {
    console.error('SHA256哈希失败:', error)
    return ''
  }
}

/**
 * SHA512哈希
 * @param {string} data 要哈希的数据
 * @returns {string} SHA512哈希值
 */
export const sha512 = (data) => {
  try {
    return CryptoJS.SHA512(String(data)).toString()
  } catch (error) {
    console.error('SHA512哈希失败:', error)
    return ''
  }
}

/**
 * Base64编码
 * @param {string} data 要编码的数据
 * @returns {string} Base64编码后的字符串
 */
export const base64Encode = (data) => {
  try {
    return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(String(data)))
  } catch (error) {
    console.error('Base64编码失败:', error)
    return ''
  }
}

/**
 * Base64解码
 * @param {string} encodedData Base64编码的数据
 * @returns {string} 解码后的字符串
 */
export const base64Decode = (encodedData) => {
  try {
    return CryptoJS.enc.Base64.parse(encodedData).toString(CryptoJS.enc.Utf8)
  } catch (error) {
    console.error('Base64解码失败:', error)
    return ''
  }
}

/**
 * URL安全的Base64编码
 * @param {string} data 要编码的数据
 * @returns {string} URL安全的Base64编码
 */
export const base64UrlEncode = (data) => {
  try {
    return base64Encode(data)
      .replace(/\+/g, '-')
      .replace(/\//g, '_')
      .replace(/=/g, '')
  } catch (error) {
    console.error('URL安全的Base64编码失败:', error)
    return ''
  }
}

/**
 * URL安全的Base64解码
 * @param {string} encodedData URL安全的Base64编码数据
 * @returns {string} 解码后的字符串
 */
export const base64UrlDecode = (encodedData) => {
  try {
    // 添加填充字符
    let data = encodedData.replace(/-/g, '+').replace(/_/g, '/')
    while (data.length % 4) {
      data += '='
    }
    return base64Decode(data)
  } catch (error) {
    console.error('URL安全的Base64解码失败:', error)
    return ''
  }
}

/**
 * 生成随机字符串
 * @param {number} length 字符串长度
 * @param {string} charset 字符集
 * @returns {string} 随机字符串
 */
export const generateRandomString = (length = 16, charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') => {
  let result = ''
  const charsetLength = charset.length
  for (let i = 0; i < length; i++) {
    result += charset.charAt(Math.floor(Math.random() * charsetLength))
  }
  return result
}

/**
 * 生成随机数字字符串
 * @param {number} length 字符串长度
 * @returns {string} 随机数字字符串
 */
export const generateRandomNumber = (length = 6) => {
  return generateRandomString(length, '0123456789')
}

/**
 * 生成UUID
 * @returns {string} UUID字符串
 */
export const generateUUID = () => {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    const r = Math.random() * 16 | 0
    const v = c === 'x' ? r : (r & 0x3 | 0x8)
    return v.toString(16)
  })
}

/**
 * 密码哈希（使用PBKDF2）
 * @param {string} password 密码
 * @param {string} salt 盐值
 * @param {number} iterations 迭代次数
 * @returns {string} 哈希后的密码
 */
export const hashPassword = (password, salt = '', iterations = 10000) => {
  try {
    const saltValue = salt || generateRandomString(16)
    const hash = CryptoJS.PBKDF2(password, saltValue, {
      keySize: 256 / 32,
      iterations: iterations
    })
    return {
      hash: hash.toString(),
      salt: saltValue
    }
  } catch (error) {
    console.error('密码哈希失败:', error)
    return { hash: '', salt: '' }
  }
}

/**
 * 验证密码
 * @param {string} password 原始密码
 * @param {string} hash 哈希值
 * @param {string} salt 盐值
 * @param {number} iterations 迭代次数
 * @returns {boolean} 是否匹配
 */
export const verifyPassword = (password, hash, salt, iterations = 10000) => {
  try {
    const result = hashPassword(password, salt, iterations)
    return result.hash === hash
  } catch (error) {
    console.error('密码验证失败:', error)
    return false
  }
}

/**
 * 生成JWT Token
 * @param {object} payload 载荷数据
 * @param {string} secret 密钥
 * @param {object} options 选项
 * @returns {string} JWT Token
 */
export const generateJWT = (payload, secret, options = {}) => {
  try {
    const header = {
      alg: 'HS256',
      typ: 'JWT'
    }
    
    const now = Math.floor(Date.now() / 1000)
    const defaultPayload = {
      iat: now,
      exp: now + (options.expiresIn || 3600) // 默认1小时过期
    }
    
    const finalPayload = { ...defaultPayload, ...payload }
    
    const encodedHeader = base64UrlEncode(JSON.stringify(header))
    const encodedPayload = base64UrlEncode(JSON.stringify(finalPayload))
    
    const signature = CryptoJS.HmacSHA256(
      `${encodedHeader}.${encodedPayload}`,
      secret
    )
    const encodedSignature = base64UrlEncode(signature.toString())
    
    return `${encodedHeader}.${encodedPayload}.${encodedSignature}`
  } catch (error) {
    console.error('生成JWT失败:', error)
    return ''
  }
}

/**
 * 验证JWT Token
 * @param {string} token JWT Token
 * @param {string} secret 密钥
 * @returns {object|null} 解码后的载荷数据
 */
export const verifyJWT = (token, secret) => {
  try {
    const parts = token.split('.')
    if (parts.length !== 3) {
      return null
    }
    
    const [encodedHeader, encodedPayload, encodedSignature] = parts
    
    // 验证签名
    const signature = base64UrlDecode(encodedSignature)
    const expectedSignature = CryptoJS.HmacSHA256(
      `${encodedHeader}.${encodedPayload}`,
      secret
    )
    
    if (signature !== expectedSignature.toString()) {
      return null
    }
    
    // 解码载荷
    const payload = JSON.parse(base64UrlDecode(encodedPayload))
    
    // 检查过期时间
    const now = Math.floor(Date.now() / 1000)
    if (payload.exp && payload.exp < now) {
      return null
    }
    
    return payload
  } catch (error) {
    console.error('验证JWT失败:', error)
    return null
  }
}

/**
 * 加密工具类
 */
export const crypto = {
  aesEncrypt,
  aesDecrypt,
  md5,
  sha256,
  sha512,
  base64Encode,
  base64Decode,
  base64UrlEncode,
  base64UrlDecode,
  generateRandomString,
  generateRandomNumber,
  generateUUID,
  hashPassword,
  verifyPassword,
  generateJWT,
  verifyJWT
}

export default crypto 